package com.easylinkin.linkappapi.space.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.calculaterule.mapper.CalculateConfigAttributeMapper;
import com.easylinkin.linkappapi.calculaterule.mapper.CalculateConfigMapper;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.exceptions.ExceptionEnum.SpaceExceptionEnum;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.entity.DeviceRefAreaScope;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.device.service.DeviceRefAreaScopeService;
import com.easylinkin.linkappapi.function.entity.TenantFunctionRefArea;
import com.easylinkin.linkappapi.function.service.TenantFunctionRefAreaService;
import com.easylinkin.linkappapi.ruleengine.mapper.RuleEngineMapper;
import com.easylinkin.linkappapi.security.constant.LinkappUserConstant;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappRole;
import com.easylinkin.linkappapi.security.entity.LinkappRoleRefSpace;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.mapper.LinkappRoleMapper;
import com.easylinkin.linkappapi.security.service.LinkappUserService;
import com.easylinkin.linkappapi.space.entity.LinkappArea;
import com.easylinkin.linkappapi.space.entity.LinkappSpace;
import com.easylinkin.linkappapi.space.mapper.LinkappSpaceMapper;
import com.easylinkin.linkappapi.space.mapper.RoleSpaceMapper;
import com.easylinkin.linkappapi.space.service.LinkappAreaService;
import com.easylinkin.linkappapi.space.service.LinkappSpaceService;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import site.morn.framework.context.AccountContext;

/**
 * <p></p>
 *
 * @author liuming
 * @since 2020/4/14
 */
@Service
public class LinkappSpaceServiceImpl extends ServiceImpl<LinkappSpaceMapper, LinkappSpace> implements LinkappSpaceService {

    @Resource
    LinkappSpaceMapper linkappSpaceMapper;
    @Resource
    LinkappAreaService linkappAreaService;
    @Resource
    LinkappUserService linkappUserService;
    @Resource
    LinkappRoleMapper linkappRoleMapper;
    @Resource
    LinkappUserContextProducer linkappUserContextProducer;
    @Resource
    DeviceMapper deviceMapper;
    @Resource
    private RuleEngineMapper ruleEngineMapper;
    @Resource
    private CalculateConfigMapper calculateConfigMapper;
    @Resource
    private CalculateConfigAttributeMapper calculateConfigAttributeMapper;
    @Resource
    private RoleSpaceMapper roleSpaceMapper;
    @Resource
    private TenantFunctionRefAreaService tenantFunctionRefAreaService;
    @Resource
    private DeviceRefAreaScopeService deviceRefAreaScopeService;
    @Resource
    private CommonService commonService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addLinkappSpace(LinkappSpace linkappSpace) {
        validParamRequired(linkappSpace);
        validParamFormat(linkappSpace);
        validRepeat(linkappSpace);
        
        Integer i = count();
        String spaceNo = String.format("%3d", i).replace(" ", "0");
        linkappSpace.setSpaceNo(spaceNo);
        
        LinkappUser user = linkappUserContextProducer.getNotNullCurrent();
        linkappSpace.setTenantId(user.getTenantId());
        linkappSpace.setCreateTime(new Date());
        commonService.setCreateAndModifyInfo(linkappSpace);
        boolean save = save(linkappSpace);

        if ("2".equals(user.getType())) {
            Collection<LinkappRole> roles = linkappRoleMapper.findByUsersId(user.getId());
            for (LinkappRole role : roles) {
                LinkappRoleRefSpace roleRefSpace = new LinkappRoleRefSpace();
                roleRefSpace.setSpaceId(linkappSpace.getId().toString());
                roleRefSpace.setTenantId(user.getTenantId());
                roleRefSpace.setRoleId(role.getId().toString());
                roleRefSpace.setId(UUID.randomUUID().toString().replaceAll("-", ""));
                linkappRoleMapper.insertRole2Spaces(roleRefSpace);
            }
            // 修改角色空间权限的时候更新这个缓存
            AccountContext.cacheGroup().clearGroup("space");
        }

        //创建一个级别为0的子节点，列表中不可见
        LinkappArea linkappArea = new LinkappArea();
        linkappArea.setAreaName(linkappSpace.getSpaceName());
        linkappArea.setAreaNo(linkappSpace.getSpaceNo());
        linkappArea.setId(linkappSpace.getId());
        linkappArea.setSpaceId(linkappSpace.getId());
        linkappArea.setLevel(0);
        linkappArea.setAreaPath(linkappSpace.getSpaceName());
        linkappArea.setTenantId(user.getTenantId());
        commonService.setCreateAndModifyInfo(linkappArea);
        linkappAreaService.save(linkappArea);
        return save;
    }

    /**
     * 校验重复项
     * @param linkappSpace 空间vo
     */
    private void validRepeat(LinkappSpace linkappSpace) {
        QueryWrapper<LinkappSpace> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("space_name", linkappSpace.getSpaceName());
        List<LinkappSpace> list = baseMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 1) {
            throw new BusinessException(SpaceExceptionEnum.SPACE_NAME_EXIST);
        }
        if (StringUtils.isEmpty(linkappSpace.getId())) {
            throw new BusinessException(SpaceExceptionEnum.SPACE_NAME_EXIST);
        }
        if (!linkappSpace.getId().equals(list.get(0).getId())) {
            throw new BusinessException(SpaceExceptionEnum.SPACE_NAME_EXIST);
        }
    }

    /**
     * 校验字段格式
     * @param linkappSpace
     */
    private void validParamFormat(LinkappSpace linkappSpace) {
        Assert.isTrue(linkappSpace.getSpaceName() == null || linkappSpace.getSpaceName().length() <= 50, "名称超长");
    }

    /**
     * 校验必填
     * @param linkappSpace
     */
    private void validParamRequired(LinkappSpace linkappSpace) {
        Assert.notNull(linkappSpace, "参数为空");
        Assert.isTrue(StringUtils.isNotBlank(linkappSpace.getSpaceName()), "空间名称不能为空");
        Assert.notNull(linkappSpace.getType(), "空间类型不能为空,(1室内 2室外)");
        Assert.isTrue(linkappSpace.getType().equals(1) || linkappSpace.getType().equals(2), "空间类型只能是1或2,(1室内 2室外)");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateLinkappSpace(LinkappSpace linkappSpace) {
        Assert.notNull(linkappSpace.getId(), "空间id不能为空");
        validParamFormat(linkappSpace);
        validRepeat(linkappSpace);

        QueryWrapper<LinkappSpace> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", "1");
        queryWrapper.eq("id", linkappSpace.getId());
        queryWrapper.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
        LinkappSpace oldLinkappSpace = getOne(queryWrapper);
        Assert.notNull(oldLinkappSpace, "空间id不存在");

        LinkappSpace linkappSpaceTemp = new LinkappSpace();
        linkappSpaceTemp.setId(linkappSpace.getId());
        linkappSpaceTemp = linkappSpaceMapper.selectLinkappSpace(linkappSpaceTemp);
        LinkappArea linkappAreaQuery = new LinkappArea();
        linkappAreaQuery.setId(linkappSpace.getId());
        List<LinkappArea> areaList = linkappAreaService.selectLinkappAreaLowLevlNodeList(linkappAreaQuery);
        for (LinkappArea linkappArea : areaList) {
            String areaPath = linkappAreaService.getReplacedNewAreaPath(linkappArea.getAreaPath(), linkappSpace.getSpaceName());
            linkappArea.setAreaPath(areaPath);
            if(linkappArea.getId().equals(linkappSpace.getId())){
                linkappArea.setAreaName(linkappSpace.getSpaceName());
            }
            commonService.setModifyInfo(linkappArea);
            linkappAreaService.updateById(linkappArea);
        }
        commonService.setModifyInfo(linkappSpace);
        boolean updateById = this.updateById(linkappSpace);

        //同步更新设备表中的areaPath
        Device deviceQuery = new Device();
        deviceQuery.setAreaPath(linkappSpaceTemp.getSpaceName().replaceAll(":","/"));
        List<Device> deviceList = deviceMapper.selectDevicesByAreaPath(deviceQuery);
        for (Device device : deviceList) {
            String deviceAreaPath = linkappAreaService.getReplacedNewAreaPath(device.getAreaPath(), linkappSpace.getSpaceName());

            device.setAreaPath(deviceAreaPath);
//            如果是室内改为室外
            if (Integer.valueOf(2).equals(linkappSpace.getType()) && !linkappSpace.getType().equals(oldLinkappSpace.getType())) {
                device.setIndoorLocation(null);
            }
            deviceMapper.updateById(device);
        }
        //同步更新租户区域绑定
        QueryWrapper<TenantFunctionRefArea> tenantFunctionRefAreaQueryWrapper = new QueryWrapper<>();
        tenantFunctionRefAreaQueryWrapper.likeRight("area_path",linkappSpaceTemp.getSpaceName().replaceAll(":","/")+":").or()
                .eq("area_path",linkappSpaceTemp.getSpaceName().replaceAll(":","/"));
        List<TenantFunctionRefArea> tenantFunctionRefAreas = tenantFunctionRefAreaService.list(tenantFunctionRefAreaQueryWrapper);
        for (TenantFunctionRefArea tenantFunctionRefArea : tenantFunctionRefAreas) {
            String deviceAreaPath = linkappAreaService.getReplacedNewAreaPath(tenantFunctionRefArea.getAreaPath(), linkappSpace.getSpaceName());
            tenantFunctionRefArea.setAreaPath(deviceAreaPath);
            UpdateWrapper updateWrapper=new UpdateWrapper();
            updateWrapper.set("area_path",deviceAreaPath);
            updateWrapper.eq("area_id",tenantFunctionRefArea.getAreaId());
            tenantFunctionRefAreaService.update(updateWrapper);
        }
        //同步更新设备绑定表
        QueryWrapper<DeviceRefAreaScope> deviceRefAreaScopeQueryWrapper = new QueryWrapper<>();
        deviceRefAreaScopeQueryWrapper.likeRight("area_path",linkappSpaceTemp.getSpaceName().replaceAll(":","/")+":").or()
                .eq("area_path",linkappSpaceTemp.getSpaceName());
        List<DeviceRefAreaScope> deviceRefAreaScopes = deviceRefAreaScopeService.list(deviceRefAreaScopeQueryWrapper);
        for (DeviceRefAreaScope deviceRefAreaScope : deviceRefAreaScopes) {
            String deviceAreaPath = linkappAreaService.getReplacedNewAreaPath(deviceRefAreaScope.getAreaPath(), linkappSpace.getSpaceName());
            deviceRefAreaScope.setAreaPath(deviceAreaPath);
            UpdateWrapper updateWrapper=new UpdateWrapper();
            updateWrapper.set("area_path",deviceAreaPath);
            updateWrapper.eq("area_id",deviceRefAreaScope.getAreaId());
            deviceRefAreaScopeService.update(updateWrapper);
        }


        return updateById;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteLinkappSpaceList(Set<String> ids) {
        Assert.notEmpty(ids,"参数为空");
        String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
        QueryWrapper qw;
        for (String id : ids) {
            qw = new QueryWrapper();
            qw.eq("id", id);
            qw.eq("tenant_id", tenantId);
            Assert.isTrue(count(qw) > 0, "当前租户下找不到id为" + id + "的空间");
        }
        
        qw = new QueryWrapper();
        qw.in("space_id", ids);
        Assert.isTrue(ruleEngineMapper.selectCount(qw) == 0, "空间被 规则引擎 用到");
        Assert.isTrue(calculateConfigMapper.selectCount(qw) == 0, "空间被 计算配置 用到");
        Assert.isTrue(calculateConfigAttributeMapper.selectCount(qw) == 0, "空间被 计算配置属性 用到");
        Assert.isTrue(roleSpaceMapper.selectCount(qw) == 0, "空间被 角色关联空间 用到");

        qw = new QueryWrapper();
        qw.in("space_id", ids);
        qw.isNotNull("parent_id");
        Assert.isTrue(linkappAreaService.count(qw) == 0, "空间被区域用到");
        
        removeByIds(ids);
        linkappAreaService.deleteLinkappAreaList(ids);
        return true;
    }

    @Override
    public List<LinkappSpace> getLinkappSpaceList(LinkappSpace linkappSpace) {
        return linkappSpaceMapper.selectLinkappSpaceList(linkappSpace);
    }


    @Override
    public List<LinkappSpace> selectLinkappSpaceList(LinkappSpace linkappSpace) {
        LinkappUser currentUser = linkappUserContextProducer.getCurrent();
        Assert.notNull(currentUser, "获取当前用户为空");
        if (LinkappUserConstant.ADMIN_TYPE.equals(currentUser.getType())) {
            return linkappSpaceMapper.selectLinkappSpaceList(new LinkappSpace());
        } else {
            return linkappUserService.selectCurrentUserSpace(currentUser.getId());
        }
    }

    @Override
    public LinkappSpace selectLinkappSpace(LinkappSpace linkappSpace) {
        return linkappSpaceMapper.selectLinkappSpace(linkappSpace);
    }
}
